#include "template.h"
/* 分数类模板，用于表示和操作有理数 */
template<class T>
struct Frac {
    T num; /* 分子 */
    T den; /* 分母 */

    /* 构造函数，初始化分数 */
    Frac(T num_, T den_) : num(num_), den(den_) {
        /* 将分母和分子同时取绝对值，避免负分数 */
        if (den < 0) {
            den = -den;
            num = -num;
        }
    }

    /* 默认构造函数，初始化为0/1 */
    Frac() : Frac(0, 1) {}

    /* 单参数构造函数，初始化为num/1 */
    Frac(T num_) : Frac(num_, 1) {}

    /* 显式类型转换操作符，将分数转换为double类型 */
    explicit operator double() const {
        return 1. * num / den;
    }

    /* 分数相加赋值操作符，实现分数相加 */
    Frac &operator+=(const Frac &rhs) {
        num = num * rhs.den + rhs.num * den;
        den *= rhs.den;
        return *this;
    }

    /* 分数相减赋值操作符，实现分数相减 */
    Frac &operator-=(const Frac &rhs) {
        num = num * rhs.den - rhs.num * den;
        den *= rhs.den;
        return *this;
    }

    /* 分数相乘赋值操作符，实现分数相乘 */
    Frac &operator*=(const Frac &rhs) {
        num *= rhs.num;
        den *= rhs.den;
        return *this;
    }

    /* 分数相除赋值操作符，实现分数相除 */
    Frac &operator/=(const Frac &rhs) {
        num *= rhs.den;
        den *= rhs.num;
        /* 确保结果为正数，避免除法后的负分数 */
        if (den < 0) {
            num = -num;
            den = -den;
        }
        return *this;
    }

    /* 分数相加操作符，实现分数相加 */
    friend Frac operator+(Frac lhs, const Frac &rhs) {
        return lhs += rhs;
    }

    /* 分数相减操作符，实现分数相减 */
    friend Frac operator-(Frac lhs, const Frac &rhs) {
        return lhs -= rhs;
    }

    /* 分数相乘操作符，实现分数相乘 */
    friend Frac operator*(Frac lhs, const Frac &rhs) {
        return lhs *= rhs;
    }

    /* 分数相除操作符，实现分数相除 */
    friend Frac operator/(Frac lhs, const Frac &rhs) {
        return lhs /= rhs;
    }

    /* 构造一个负分数 */
    friend Frac operator-(const Frac &a) {
        return Frac(-a.num, a.den);
    }

    /* 判断两个分数是否相等 */
    friend bool operator==(const Frac &lhs, const Frac &rhs) {
        return lhs.num * rhs.den == rhs.num * lhs.den;
    }

    /* 判断两个分数是否不相等 */
    friend bool operator!=(const Frac &lhs, const Frac &rhs) {
        return lhs.num * rhs.den != rhs.num * lhs.den;
    }

    /* 判断一个分数是否小于另一个分数 */
    friend bool operator<(const Frac &lhs, const Frac &rhs) {
        return lhs.num * rhs.den < rhs.num * lhs.den;
    }

    /* 判断一个分数是否大于另一个分数 */
    friend bool operator>(const Frac &lhs, const Frac &rhs) {
        return lhs.num * rhs.den > rhs.num * lhs.den;
    }

    /* 判断一个分数是否小于等于另一个分数 */
    friend bool operator<=(const Frac &lhs, const Frac &rhs) {
        return lhs.num * rhs.den <= rhs.num * lhs.den;
    }

    /* 判断一个分数是否大于等于另一个分数 */
    friend bool operator>=(const Frac &lhs, const Frac &rhs) {
        return lhs.num * rhs.den >= rhs.num * lhs.den;
    }

    /* 输出分数，先计算最大公约数，简化输出形式 */
    friend std::ostream &operator<<(std::ostream &os, Frac x) {
        T g = std::gcd(x.num, x.den);
        if (x.den == g) {
            return os << x.num / g;
        } else {
            return os << x.num / g << "/" << x.den / g;
        }
    }
};
